home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / uwsrc.arc / KERMIT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-29  |  38.6 KB  |  1,159 lines

  1. #define EXTRADEBUG
  2. /*
  3.  *  K e r m i t  File Transfer Utility seriously hacked for local use with uw
  4.  *
  5.  *  Currently allows only one kermit session to exist in one window concurent.
  6.  *
  7.  *  Adapted from UNIX Kermit, Columbia University, 1981, 1982, 1983
  8.  *      Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
  9.  *
  10.  *  Also:   Jim Guyton, Rand Corporation
  11.  *          Walter Underwood, Ford Aerospace
  12.  *
  13.  */
  14.  
  15. /*
  16.  * March 28, 1988
  17.  *        Hacked into form usable in uw.  Converted fsm's to be driven
  18.  *        by received packet events.  Rewrote rpack routine.
  19.  */
  20.  
  21. #include <obdefs.h>
  22. #include <gemdefs.h>
  23. #include <osbind.h>
  24. #include <stdio.h>          /* Standard UNIX definitions */
  25. #include <time.h>
  26. #include "wind.h"
  27. #include "windefs.h"
  28.  
  29. #define error printmsg
  30. #define chari int        /* items of type chari should be char, but, mwc
  31.                  insists on adjusting them to int anyway */
  32. /* Symbol Definitions */
  33.  
  34. #define MAXPACKSIZ  94      /* Maximum packet size */
  35. #define SOH         1       /* Start of header */
  36. #define CR          13      /* ASCII Carriage Return */
  37. #define SP          32      /* ASCII space */
  38. #define DEL         127     /* Delete (rubout) */
  39.  
  40. #define MAXTRY      10      /* Times to retry a packet */
  41. #define MYQUOTE     '#'     /* Quote character I will use */
  42. #define MYPAD       0       /* Number of padding characters I will need */
  43. #define MYPCHAR     0       /* Padding character I need (NULL) */
  44.  
  45. #define MYEOL       '\r'    /* End-Of-Line character I need */
  46.  
  47. #define MYTIME      10      /* Seconds after which I should be timed out */
  48. #define MAXTIM      60      /* Maximum timeout interval */
  49. #define MINTIM      10      /* Minumum timeout interval */
  50.  
  51. #ifndef TRUE
  52. #define TRUE        -1      /* Boolean constants */
  53. #endif
  54. #define FALSE       0
  55. #define GETPACK     2        /* return constant */
  56.  
  57. /* Macro Definitions */
  58.  
  59. /*
  60.  *  f l u s h i n p u t
  61.  *
  62.  *  Dump all pending input to clear stacked up NACK's.
  63.  */
  64.  
  65. #define flushinput()    /* no explicit call to flush needed for uw */
  66.  
  67. /*
  68.  * tochar: converts a control character to a printable one by adding a space.
  69.  *
  70.  * unchar: undoes tochar.
  71.  *
  72.  * ctl:    converts between control characters and printable characters by
  73.  *         toggling the control bit (ie. ^A becomes A and A becomes ^A).
  74.  */
  75. #define tochar(ch)  ((ch) + ' ')
  76. #define unchar(ch)  ((ch) - ' ')
  77. #define ctl(ch)     ((ch) ^ 64 )
  78. #define abs(exp) (((exp) >= 0) ? (exp) : -(exp))
  79.  
  80.  
  81. /* Global Variables */
  82.  
  83. extern int    mouse;                /* is mouse visible ? */
  84. extern    struct    wi_str    w[];
  85.  
  86. int     size,               /* Size of present data */
  87.         rpsiz,              /* Maximum receive packet size */
  88.         spsiz,              /* Maximum send packet size */
  89.         pad,                /* How much padding to send */
  90.         reqtimint,          /* timeout interval I request */
  91.         timint,             /* Timeout for foreign host on sends */
  92.         n,                  /* Packet number */
  93.         numtry,             /* Times this packet retried */
  94.         oldtry,             /* Times previous packet retried */
  95.         image,              /* -1 means 8-bit mode */
  96.         debug,              /* indicates level of debugging output (0=none) */
  97.         filnamcnv,          /* -1 means do file name case conversions */
  98.         filecount,          /* Number of files left to send */
  99.     kermwdes,        /* Window descripter for kermit window */
  100.     kermport;        /* port number for kermit window */
  101.  
  102. clock_t    timestamp;        /* Time last packet was received */
  103.  
  104. char    sflg, rflg;         /* flags for RECEIVE, SEND */
  105. char    state,              /* Present state of the automaton */
  106.         padchar,            /* Padding character to send */
  107.         eol,                /* End-Of-Line character to send */
  108.         quote,              /* Quote character in incoming data */
  109.         **filelist,         /* List of files to be sent */
  110.     *filnam,            /* Current file name */
  111.         recpkt[MAXPACKSIZ+1], /* Receive packet buffer */
  112.         packet[MAXPACKSIZ+1]; /* Packet buffer */
  113.  
  114. FILE    *fp,                /* File pointer for current disk file */
  115.         *log;               /* File pointer for Logfile */
  116.  
  117.  
  118. /*
  119.  *  kerminit
  120.  *
  121.  *  initalization routine - initalize and dispatch to the appropriate routine.
  122.  */
  123.  
  124. int kerminit(curwin)
  125. int curwin;
  126. {
  127.     OBJECT *obj_tmp;
  128.     static char path[40] = ".\*.*";
  129.     static char file[40] = "";
  130.     static char filename[80];        /* space for file and directory */
  131.     int butt;
  132.  
  133. /*  Initialize these values and hope the first packet will get across OK */
  134.  
  135.     if (kermwdes && w[kermwdes].kerm_act) return (-1);
  136.     kermwdes = curwin;
  137.                         /* If kermit already active, return. */
  138.     w[kermwdes].kerm_act = TRUE;    /* mark current window to send output
  139.                            to kermit instead of emulator */
  140.     kermport = find_port(curwin);
  141.     eol = CR;                           /* EOL for outgoing packets */
  142.     quote = '#';                        /* Standard control-quote char "#" */
  143.     pad = 0;                            /* No padding */
  144.     padchar = '\0';                     /* Use null if any padding wanted */
  145.     timint = MYTIME;                    /* default timint */
  146.  
  147.  
  148. /*
  149.  * Set direction and paramaters debug, filnamcnv, image with dialog
  150.  */
  151.     rsrc_gaddr(R_TREE, KERMPARM, &obj_tmp);
  152.     if (obj_tmp[ASCIIMOD].ob_state == NORMAL &&
  153.       obj_tmp[IMAGEMOD].ob_state == NORMAL)
  154.     {                    /* initalize object and statics */
  155.         objc_change(obj_tmp, ASCIIMOD, 0, 0, 0, 0, 0, SELECTED, 0);
  156.         objc_change(obj_tmp, CONVNAME, 0, 0, 0, 0, 0, SELECTED, 0);
  157.         objc_change(obj_tmp, RECFILE, 0, 0, 0, 0, 0, SELECTED, 0);
  158.  
  159.     path[0] = Dgetdrv() + 'a';
  160.     path[1] = ':';
  161.     Dgetpath(path+2, 0);
  162.     strcat(path, "\\*.*");
  163.     }
  164.     if ((butt = s_dial(KERMPARM, 3)) == KERMEXIT) return(kermterm());
  165.     if (obj_tmp[DEBUGENA].ob_state == SELECTED)
  166.     {
  167.         debug = obj_tmp[DEBUG1].ob_state + obj_tmp[DEBUG2].ob_state
  168.     + obj_tmp[DEBUG3].ob_state;
  169.     }
  170.     if (butt == RECFILE) obj_tmp[RECFILE].ob_state = SELECTED;
  171.     if (butt == SENDFILE) obj_tmp[SENDFILE].ob_state = SELECTED;
  172.     rflg = obj_tmp[RECFILE].ob_state;
  173.     sflg = obj_tmp[SENDFILE].ob_state;
  174.     image = (obj_tmp[IMAGEMOD].ob_state == SELECTED);
  175.     filnamcnv = obj_tmp[CONVNAME].ob_state; /* conversion for UNIX systems */
  176.     
  177. /* All set up, now execute the command that was given. */
  178.  
  179.     if (debug)
  180.     {
  181.         printmsg("debuging level = %d\n",debug);
  182.  
  183.         if (sflg) printmsg("Send command\n");
  184.         if (rflg) printmsg("Receive command\n");
  185.     }
  186.   
  187.     if (sflg)                           /* Send command */ 
  188.     {
  189.         extern char * rindex();
  190.  
  191.     if (!mouse)
  192.     {
  193.         graf_mouse(M_ON, NULL);
  194.         ++mouse;
  195.     }
  196.         fsel_input(path, file, &butt);
  197.     if (! butt) return(kermterm()); 
  198.     strcpy(filename, path);
  199.     if (debug > 2) printmsg("directory %s", filename);
  200.     filnam = rindex(filename, '\\');
  201.     if (filnam) *(++filnam) = '\0';
  202.     strcat(filename, file);
  203.         filnam = filename;        /* Get file to send */
  204.         if (debug > 2) printmsg("sending %s",filnam);
  205.         fp = NULL;                      /* Indicate no file open yet */
  206.         filelist = NULL;                /* Set up the rest of the file list */
  207.         filecount = 0;                  /* Number of files left to send */
  208.     state = 'S';                    /* Send initiate is the start state */
  209.     n = 0;                          /* Initialize message number */
  210.     numtry = 0;                     /* Say no tries yet */
  211.         w[kermwdes].kerm_act = TRUE;    /* mark current window to send output
  212.                            to kermit instead of emulator */
  213.     timestamp = clock();        /* reset timer */
  214.     sendsw();
  215.     }
  216.  
  217.     if (rflg)                           /* Receive command */
  218.     {
  219.     state = 'R';                    /* Receive-Init is the start state */
  220.     n = 0;                          /* Initialize message number */
  221.     numtry = 0;                     /* Say no tries yet */
  222.     timestamp = clock();        /* reset timer */
  223.     }
  224.     
  225.     return(0);
  226. }
  227.  
  228. /*
  229.  * kermterm - Terminate kermit and tell uw not to call us again.
  230.  */
  231. kermterm()
  232. {
  233.     sflg = rflg = 0;
  234.     w[kermwdes].kerm_act = FALSE;
  235.     kermwdes = 0;
  236. }
  237.  
  238. kermtimchk()
  239. {
  240.     if (!w[kermwdes].kerm_act)    /* is kermit active? */
  241.     {
  242.     kermwdes = 0;
  243.     return;
  244.     }
  245.     if ((clock() - timestamp) / CLK_TCK > timint)    /* timeout ? */
  246.     {
  247.     rpack(NULL, "", "");    /* tell FSM about time out */
  248.     }
  249. }
  250.  
  251. /*
  252.  *  s e n d s w
  253.  *
  254.  *  Sendsw is the state table switcher for sending files.  It loops until
  255.  *  either it finishes, or an error is encountered.  The routines called
  256.  *  by sendsw are responsible for changing the state.
  257.  *
  258.  */
  259.  
  260. int sendsw()
  261. {
  262.     chari sinit(), sfile(), sdata(), seof(), sbreak(), nstate;
  263.  
  264.     nstate = state;
  265.     while(TRUE)                         /* Do this as long as necessary */
  266.     {
  267.         if (debug) printmsg("sendsw state: %c  nstate: %c\n",state,nstate);
  268.     while (nstate != 'I')
  269.     {
  270.             switch(nstate)
  271.             {
  272.                 case 'S':   nstate = sinit();  break; /* Send-Init */
  273.                 case 'F':   nstate = sfile();  break; /* Send-File */
  274.                 case 'D':   nstate = sdata();  break; /* Send-Data */
  275.                 case 'Z':   nstate = seof();   break; /* Send-End-of-File */
  276.                 case 'B':   nstate = sbreak(); break; /* Send-Break */
  277.             }
  278.         switch(nstate)
  279.         {
  280.                 case 'C':   printmsg("\aDone.\a");
  281.                     return (TRUE);           /* Complete */
  282.                 case 'A':   printmsg("Send Failed.");
  283.                     return (FALSE);          /* "Abort" */
  284.         }
  285.         if (nstate != 'I')
  286.         {
  287.             state = nstate;
  288.             if (numtry++ > MAXTRY) return(FALSE); /* If too many tries, give up */
  289.         }
  290.     }
  291.     return(GETPACK);
  292.     }
  293. }
  294.  
  295.  
  296. /*
  297.  *  s i n i t
  298.  *
  299.  *  Send Initiate: send this host's parameters and get other side's back.
  300.  */
  301.  
  302. chari sinit()
  303. {
  304.     int num, len;                       /* Packet number, length */
  305.     static int sent = 0;
  306.  
  307.     if (! sent) {
  308.     reqtimint = MYTIME;
  309.     spar(packet);                   /* Fill up init info packet */
  310.     flushinput();                   /* Flush pending input */
  311.     spack('S',n,6,packet);          /* Send an S packet */
  312.  
  313.     sent = 1;
  314.     return('I');            /* get packet to read */
  315.     }
  316.     sent = 0;
  317.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  318.     {
  319.         case 'N':  return(state);       /* NAK, try it again */
  320.  
  321.         case 'Y':                       /* ACK */
  322.             if (n != num)               /* If wrong ACK, stay in S state */
  323.                 return(state);          /* and try again */
  324.             rpar(recpkt);               /* Get other side's init info */
  325.  
  326.             if (eol == 0) eol = '\n';   /* Check and set defaults */
  327.             if (quote == 0) quote = '#';
  328.             if(abs(timint - reqtimint) < 3) timint = reqtimint + 3;
  329.             /* guarentee diference of > 3 for sounds for timint */
  330.  
  331.             numtry = 0;                 /* Reset try counter */
  332.             n = (n+1)%64;               /* Bump packet count */
  333.             return('F');                /* OK, switch state to F */
  334.  
  335.         case 'E':                       /* Error packet received */
  336.             prerrpkt(recpkt);           /* Print it out and */
  337.             return('A');                /* abort */
  338.  
  339.         case FALSE: return(state);      /* Receive failure, try again */
  340.  
  341.         default: return('A');           /* Anything else, just "abort" */
  342.    }
  343.  }
  344.  
  345.  
  346. /*
  347.  *  s f i l e
  348.  *
  349.  *  Send File Header.
  350.  */
  351.  
  352. chari sfile()
  353. {
  354.     int num, len;                       /* Packet number, length */
  355.     char filnam1[50],                   /* Converted file name */
  356.         *newfilnam,                     /* Pointer to file name to send */
  357.         *cp;                            /* char pointer */
  358.     static int sent = 0;
  359.  
  360.     if (! sent) {
  361.         if (fp == NULL)                     /* If not already open, */
  362.         {   if (debug) printmsg("   Opening %s for sending.\n",filnam);
  363.             fp = fopen(filnam, image ? "rb" : "r");         /* open the file to be sent */
  364.             if (fp == NULL)                 /* If bad file pointer, give up */
  365.             {
  366.                 error("Cannot open file %s",filnam);
  367.                 return('A');
  368.             }
  369.         }
  370.  
  371.         strcpy(filnam1, filnam);            /* Copy file name */
  372.         newfilnam = cp = filnam1;
  373.         while (*cp != '\0')                 /* Strip off all leading directory */
  374.             if (*cp++ == '\\')               /* names (ie. up to the last /). */
  375.                 newfilnam = cp;
  376.  
  377.         if (filnamcnv)                      /* Convert lower case to upper  */
  378.             for (cp = newfilnam; *cp != '\0'; cp++)
  379.                 if (*cp >= 'a' && *cp <= 'z')
  380.                     *cp ^= 040;
  381.  
  382.         len = cp - newfilnam;               /* Compute length of new filename */
  383.  
  384.         printmsg("Sending %s as %s",filnam,newfilnam);
  385.  
  386.         spack('F',n,len,newfilnam);         /* Send an F packet */
  387.     sent = 1;
  388.     
  389.     return('I');            /* get packet to read */
  390.     }
  391.     sent = 0;
  392.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  393.     {                   
  394.         case 'N':                       /* NAK, just stay in this state, */
  395.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  396.             if (n != num)               /* which is just like an ACK for */ 
  397.                 return(state);          /* this packet so fall thru to... */
  398.  
  399.         case 'Y':                       /* ACK */
  400.             if (n != num) return(state); /* If wrong ACK, stay in F state */
  401.             numtry = 0;                 /* Reset try counter */
  402.             n = (n+1)%64;               /* Bump packet count */
  403.             size = bufill(packet);      /* Get first data from file */
  404.             return('D');                /* Switch state to D */
  405.  
  406.         case 'E':                       /* Error packet received */
  407.             prerrpkt(recpkt);           /* Print it out and */
  408.             return('A');                /* abort */
  409.  
  410.         case FALSE: return(state);      /* Receive failure, stay in F state */
  411.  
  412.         default:    return('A');        /* Something else, just "abort" */
  413.     }
  414. }
  415.  
  416.  
  417. /*
  418.  *  s d a t a
  419.  *
  420.  *  Send File Data
  421.  */
  422.  
  423. chari sdata()
  424. {
  425.     int num, len;                       /* Packet number, length */
  426.     static int sent = 0;
  427.  
  428.     if (! sent) {
  429.         spack('D',n,size,packet);           /* Send a D packet */
  430.     sent = 1;
  431.     return('I');            /* get packet to read */
  432.     }
  433.     sent = 0;
  434.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  435.     {               
  436.         case 'N':                       /* NAK, just stay in this state, */
  437.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet */
  438.             if (n != num)               /* which is just like an ACK for */
  439.                 return(state);          /* this packet so fall thru to... */
  440.                 
  441.         case 'Y':                       /* ACK */
  442.             if (n != num) return(state); /* If wrong ACK, fail */
  443.             numtry = 0;                 /* Reset try counter */
  444.             n = (n+1)%64;               /* Bump packet count */
  445.             if ((size = bufill(packet)) == EOF) /* Get data from file */
  446.                 return('Z');            /* If EOF set state to that */
  447.             return('D');                /* Got data, stay in state D */
  448.  
  449.         case 'E':                       /* Error packet received */
  450.             prerrpkt(recpkt);           /* Print it out and */
  451.             return('A');                /* abort */
  452.  
  453.         case FALSE: return(state);      /* Receive failure, stay in D */
  454.  
  455.         default:    return('A');        /* Anything else, "abort" */
  456.     }
  457. }
  458.  
  459.  
  460. /*
  461.  *  s e o f
  462.  *
  463.  *  Send End-Of-File.
  464.  */
  465.  
  466. chari seof()
  467. {
  468.     int num, len;                       /* Packet number, length */
  469.     static int sent = 0;
  470.  
  471.     if (! sent) {
  472.         spack('Z',n,0,packet);              /* Send a 'Z' packet */
  473.  
  474.     sent = 1;
  475.     return('I');            /* get packet to read */
  476.     }
  477.     sent = 0;
  478.     switch(rpack(&len,&num,recpkt))     /* What was the reply? */
  479.     {
  480.         case 'N':                       /* NAK, just stay in this state, */
  481.             num = (--num<0 ? 63:num);   /* unless it's NAK for next packet, */
  482.             if (n != num)               /* which is just like an ACK for */
  483.                 return(state);          /* this packet so fall thru to... */
  484.  
  485.         case 'Y':                       /* ACK */
  486.             if (n != num) return(state); /* If wrong ACK, hold out */
  487.             numtry = 0;                 /* Reset try counter */
  488.             n = (n+1)%64;               /* and bump packet count */
  489.             if (debug) printmsg("   Closing input file %s, ",filnam);
  490.             fclose(fp);                 /* Close the input file */
  491.             fp = NULL;                  /* Set flag indicating no file open */ 
  492.  
  493.             if (debug) printmsg("looking for next file...\n");
  494.             if (gnxtfl() == FALSE)      /* No more files go? */
  495.                 return('B');            /* if not, break, EOT, all done */
  496.             if (debug) printmsg("   New file is %s\n",filnam);
  497.             return('F');                /* More files, switch state to F */
  498.  
  499.         case 'E':                       /* Error packet received */
  500.             prerrpkt(recpkt);           /* Print it out and */
  501.             return('A');                /* abort */
  502.  
  503.         case FALSE: return(state);      /* Receive failure, stay in Z */
  504.  
  505.         default:    return('A');        /* Something else, "abort" */
  506.     }
  507. }
  508.  
  509.  
  510. /*
  511.  *  s b r e a k
  512.  *
  513.  *  Send Break (EOT)
  514.  */
  515.  
  516. chari sbreak()
  517. {
  518.     int num, len;                       /* Packet number, length */
  519.     static int sent = 0;
  520.  
  521.     if (! sent) {
  522.         spack('B',n,0,packet);              /* Send a B packet */
  523.  
  524.     sent = 1;
  525.     return('I');            /* get packet to read */
  526.     }
  527.     sent = 0;
  528.     switch (rpack(&len,&num,recpkt))    /* What was the reply? */
  529.     {
  530.         case 'N':                       /* NAK, just stay in this state, */
  531.             num = (--num<0 ? 63:num);   /* unless NAK for previous packet, */
  532.             if (n != num)               /* which is just like an ACK for */
  533.                 return(state);          /* this packet so fall thru to... */
  534.  
  535.         case 'Y':                       /* ACK */
  536.             if (n != num) return(state); /* If wrong ACK, fail */
  537.             numtry = 0;                 /* Reset try counter */
  538.             n = (n+1)%64;               /* and bump packet count */
  539.             return('C');                /* Switch state to Complete */
  540.  
  541.         case 'E':                       /* Error packet received */
  542.             prerrpkt(recpkt);           /* Print it out and */
  543.             return('A');                /* abort */
  544.  
  545.         case FALSE: return(state);      /* Receive failure, stay in B */
  546.  
  547.         default:    return ('A');       /* Other, "abort" */
  548.    }
  549. }
  550.  
  551.  
  552. /*
  553.  *  r e c s w
  554.  *
  555.  *  This is the state table switcher for receiving files.
  556.  */
  557.  
  558.  
  559.  
  560.  
  561. recsw()
  562. {
  563.     chari rinit(), rfile(), rdata();     /* Use these procedures */
  564.  
  565.     if (debug) printmsg(" recsw state: %c\n",state);
  566.     switch(state)                   /* Do until done */
  567.     {
  568.         case 'R':   state = rinit(); break; /* Receive-Init */
  569.         case 'F':   state = rfile(); break; /* Receive-File */
  570.         case 'D':   state = rdata(); break; /* Receive-Data */
  571.     }
  572.     if (numtry++ > MAXTRY) return(FALSE); /* If too many tries, give up */
  573.     switch(state)                   /* Do until done */
  574.     {
  575.         case 'C':   printmsg("\aDone.\a");
  576.             return(TRUE);           /* Complete state */
  577.         case 'A':   printmsg("Receive Failed.");
  578.             return(FALSE);          /* "Abort" state */
  579.     }
  580.     return(GETPACK);                /* get the next packet */
  581. }
  582.  
  583.     
  584. /*
  585.  *  r i n i t
  586.  *
  587.  *  Receive Initialization
  588.  */
  589.   
  590. chari rinit()
  591. {
  592.     int len, num;                       /* Packet length, number */
  593.  
  594.     switch(rpack(&len,&num,packet))     /* Get a packet */
  595.     {
  596.         case 'S':                       /* Send-Init */
  597.             rpar(packet);               /* Get the other side's init data */
  598.             if (timint > MYTIME + 3) reqtimint = timint - 4;
  599.             else reqtimint = timint + 4;
  600.             spar(packet);               /* Fill up packet with my init info */
  601.             flushinput();               /* get rid of unwanted nak's */
  602.             spack('Y',n,6,packet);      /* ACK with my parameters */
  603.             oldtry = numtry;            /* Save old try count */
  604.             numtry = 0;                 /* Start a new counter */
  605.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  606.             return('F');                /* Enter File-Receive state */
  607.  
  608.         case 'E':                       /* Error packet received */
  609.             prerrpkt(recpkt);           /* Print it out and */
  610.             return('A');                /* abort */
  611.  
  612.         case FALSE:                     /* Didn't get packet */
  613.             spack('N',n,0,NULL);        /* Return a NAK */
  614.             return(state);              /* Keep trying */
  615.  
  616.         default:     return('A');       /* Some other packet type, "abort" */
  617.     }
  618. }
  619.  
  620.  
  621. /*
  622.  *  r f i l e
  623.  *
  624.  *  Receive File Header
  625.  */
  626.  
  627. chari rfile()
  628. {
  629.     int num, len;                       /* Packet number, length */
  630.     char filnam1[50];                   /* Holds the converted file name */
  631.  
  632.     switch(rpack(&len,&num,packet))     /* Get a packet */
  633.     {
  634.         case 'S':                       /* Send-Init, maybe our ACK lost */
  635.             if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
  636.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  637.             {                           /* Yes, ACK it again with  */
  638.                 spar(packet);           /* our Send-Init parameters */
  639.                 spack('Y',num,6,packet);
  640.                 numtry = 0;             /* Reset try counter */
  641.                 return(state);          /* Stay in this state */
  642.             }
  643.             else return('A');           /* Not previous packet, "abort" */
  644.  
  645.         case 'Z':                       /* End-Of-File */
  646.             if (oldtry++ > MAXTRY) return('A');
  647.             if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
  648.             {                           /* Yes, ACK it again. */
  649.                 spack('Y',num,0,NULL);
  650.                 numtry = 0;
  651.                 return(state);          /* Stay in this state */
  652.             }
  653.             else return('A');           /* Not previous packet, "abort" */
  654.  
  655.         case 'F':                       /* File Header (just what we want) */
  656.             if (num != n) return('A');  /* The packet number must be right */
  657.             strcpy(filnam1, packet);    /* Copy the file name */
  658.  
  659.             if (filnamcnv)              /* Convert upper case to lower */
  660.                 for (filnam=filnam1; *filnam != '\0'; filnam++)
  661.                     if (*filnam >= 'A' && *filnam <= 'Z')
  662.                         *filnam |= 040;
  663.  
  664.             if ((fp=fopen(filnam1, image ? "wb" : "w"))==NULL) /* Try to open a new file */
  665.             {
  666.                 error("Cannot create %s",filnam1); /* Give up if can't */
  667.                 return('A');
  668.             }
  669.             else                        /* OK, give message */
  670.  
  671.                 printmsg("Receiving %s as %s",packet,filnam1);
  672.  
  673.             spack('Y',n,0,NULL);        /* Acknowledge the file header */
  674.             oldtry = numtry;            /* Reset try counters */
  675.             numtry = 0;                 /* ... */
  676.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  677.             return('D');                /* Switch to Data state */
  678.  
  679.         case 'B':                       /* Break transmission (EOT) */
  680.             if (num != n) return ('A'); /* Need right packet number here */
  681.             spack('Y',n,0,NULL);        /* Say OK */
  682.             return('C');                /* Go to complete state */
  683.  
  684.         case 'E':                       /* Error packet received */
  685.             prerrpkt(recpkt);           /* Print it out and */
  686.             return('A');                /* abort */
  687.  
  688.         case FALSE:                     /* Didn't get packet */
  689.             spack('N',n,0,NULL);        /* Return a NAK */
  690.             return(state);              /* Keep trying */
  691.  
  692.         default:    return ('A');       /* Some other packet, "abort" */
  693.     }
  694. }
  695.  
  696.  
  697. /*
  698.  *  r d a t a
  699.  *
  700.  *  Receive Data
  701.  */
  702.  
  703. chari rdata()
  704. {
  705.     int num, len;                       /* Packet number, length */
  706.  
  707.     switch(rpack(&len,&num,packet))     /* Get packet */
  708.     {
  709.         case 'D':                       /* Got Data packet */
  710. #ifdef EXTRADEBUG
  711.         if (debug > 2) printmsg("Got Data Packet");
  712. #endif
  713.             if (num != n)               /* Right packet? */
  714.             {                           /* No */
  715.                 if (oldtry++ > MAXTRY)
  716.                     return('A');        /* If too many tries, abort */
  717.                 if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  718.                 {                       /* Previous packet again? */
  719.                     spack('Y',num,6,packet); /* Yes, re-ACK it */
  720.                     numtry = 0;         /* Reset try counter */
  721.                     return(state);      /* Don't write out data! */
  722.                 }
  723.                 else return('A');       /* sorry, wrong number */
  724.             }
  725.             /* Got data with right packet number */
  726.             spack('Y',n,0,NULL);        /* Acknowledge the packet */
  727. #ifdef EXTRADEBUG
  728.         if (debug > 2) printmsg("Calling bufemp");
  729. #endif
  730.             bufemp(packet,len);         /* Write the data to the file */
  731.             oldtry = numtry;            /* Reset the try counters */
  732.             numtry = 0;                 /* ... */
  733.             n = (n+1)%64;               /* Bump packet number, mod 64 */
  734.             return('D');                /* Remain in data state */
  735.  
  736.         case 'F':                       /* Got a File Header */
  737.             if (oldtry++ > MAXTRY)
  738.                 return('A');            /* If too many tries, "abort" */
  739.             if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
  740.             {                           /* It was the previous one */
  741.                 spack('Y',num,0,NULL);  /* ACK it again */
  742.                 numtry = 0;             /* Reset try counter */
  743.                 return(state);          /* Stay in Data state */
  744.             }
  745.             else return('A');           /* Not previous packet, "abort" */
  746.  
  747.         case 'Z':                       /* End-Of-File */
  748.             if (num != n) return('A');  /* Must have right packet number */
  749.             spack('Y',n,0,NULL);        /* OK, ACK it. */
  750.             fclose(fp);                 /* Close the file */
  751.             n = (n+1)%64;               /* Bump packet number */
  752.             return('F');                /* Go back to Receive File state */
  753.  
  754.         case 'E':                       /* Error packet received */
  755.             prerrpkt(recpkt);           /* Print it out and */
  756.             return('A');                /* abort */
  757.  
  758.         case FALSE:                     /* Didn't get packet */
  759.             spack('N',n,0,NULL);        /* Return a NAK */
  760.             return(state);              /* Keep trying */
  761.  
  762.         default:     return('A');       /* Some other packet, "abort" */
  763.     }
  764. }
  765.  
  766.  
  767. /*
  768.  *      KERMIT utilities.
  769.  */
  770.  
  771.  
  772. /*
  773.  *  s p a c k
  774.  *
  775.  *  Send a Packet
  776.  */
  777.  
  778. spack(type,num,len,data)
  779. chari type;
  780. char  *data;
  781. int num, len;
  782. {
  783.     int i;                              /* Character loop counter */
  784.     char chksum, buffer[100];           /* Checksum, packet buffer */
  785.     register char *bufp;                /* Buffer pointer */
  786.  
  787.     if (debug>1)                        /* Display outgoing packet */
  788.     {
  789.         printmsg("  spack type: %c\n",type);
  790.         printmsg("         num:  %d\n",num);
  791.         printmsg("         len:  %d\n",len);
  792.         if (data != NULL)
  793.     {
  794.             data[len] = '\0';           /* Null-terminate data to print it */
  795.             printmsg("        data: \"%s\"\n",data);
  796.     }
  797.     }
  798.   
  799.     bufp = buffer;                      /* Set up buffer pointer */
  800.     for (i=1; i<=pad; i++) proto_out(kermport,&padchar,1); /* Issue any padding */
  801.  
  802.     *bufp++ = SOH;                      /* Packet marker, ASCII 1 (SOH) */
  803.     *bufp++ = tochar(len+3);            /* Send the character count */
  804.     chksum  = tochar(len+3);            /* Initialize the checksum */
  805.     *bufp++ = tochar(num);              /* Packet number */
  806.     chksum += tochar(num);              /* Update checksum */
  807.     *bufp++ = type;                     /* Packet type */
  808.     chksum += type;                     /* Update checksum */
  809.  
  810.     for (i=0; i<len; i++)               /* Loop for all data characters */
  811.     {
  812.         *bufp++ = data[i];              /* Get a character */
  813.         chksum += data[i];              /* Update checksum */
  814.     }
  815.     chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
  816.     *bufp++ = tochar(chksum);           /* Put it in the packet */
  817.     *bufp = eol;                        /* Extra-packet line terminator */
  818.     proto_out(kermport, buffer, bufp-buffer+1);
  819.                         /* Send the packet */
  820. #ifdef EXTRADEBUG
  821.     if (debug > 2) printmsg("Returning from spack");
  822. #endif
  823. }
  824.  
  825. /*
  826.  *  r p a c k
  827.  *
  828.  *  Read a Packet
  829.  *  This routine is called both to buffer data from the host to the kermit
  830.  *  window and to retreive those buffers once they contain a packet.  This
  831.  *  routine calls the kermit state machine when it has a complete packet.
  832.  *  The kermit state machine in turn calls this routine to retreive the packet.
  833.  *  Thus, this routine is indirectly recursive to two levels.  Receive timeouts
  834.  *  and bad packets cause FALSE to be returned to the state machine.  The uw
  835.  *  control loop calls us with num == NULL to pass us a string of data from
  836.  *  the host.  The uw control loop calls us with len == NULL if the timout
  837.  *  counter (kerm_time) exceeds timint without us reseting it.
  838.  */
  839. #ifdef EXTRADEBUG
  840. #define getnext {t = *dptr++; \
  841.             if (debug>2) printmsg( "char %d state %c", t, recstate);\
  842.         if ((t & 0177) == SOH) { \
  843.             recstate = 'L'; /* restart packet collection */\
  844.             break; } \
  845.         if (!image) t &= 0177;    /* Handle parity */ \
  846.         if (t == 0) break; /* end of this input buffer */ }
  847. #else
  848. #define getnext {t = *dptr++; \
  849.         if ((t & 0177) == SOH) { \
  850.             recstate = 'L'; /* restart packet collection */\
  851.             break; } \
  852.         if (!image) t &= 0177;    /* Handle parity */ \
  853.         if (t == 0) break; /* end of this input buffer */ }
  854. #endif
  855. rpack(len,num,data)
  856. int *len, *num;                         /* Packet length, number */
  857. char *data;                             /* Packet data */
  858. {
  859.     static int i;                       /* Data character number */
  860.     static int leng;            /* length of data packet in buffer */
  861.     static char type;            /* packet type */
  862.     static int numb;            /* number of data packet in buffer */
  863.     static int timedout = 0;        /* did we time out? */
  864.     char t;                             /* Current input character */
  865.     static char cchksum,                        /* Our (computed) checksum */
  866.         rchksum;                        /* Checksum received from other host */
  867.     char *dptr;                /* pointer to next data byte */
  868.     static char mybuf[MAXPACKSIZ];    /* buffer used to acumulate packet */
  869.     static char recstate = 'S';        /* start with S state */
  870.  
  871.     if (len == NULL) {    /* timed out */
  872.         timedout = TRUE;
  873.     if (sflg)
  874.     {
  875.         if (sendsw() != GETPACK)    /* Send the file(s) */
  876.                 return(kermterm());
  877.     }
  878.     else if (rflg)
  879.     {
  880.             if (recsw() != GETPACK)     /* Receive the file(s) */
  881.                 return(kermterm());
  882.     }
  883.         return (0);
  884.     }
  885.     if (len != NULL && num != NULL)    /* received packet or timed out */
  886.     {
  887.     *len = leng;
  888.     *num = numb;
  889.     timestamp = clock();        /* reset timer */
  890.     if (timedout)
  891.     {
  892.         printmsg("Timeout.");
  893.         timedout = 0;
  894.         return(FALSE);
  895.     }
  896.     for (i=0; i<leng; i++)
  897.         data[i] = mybuf[i];
  898.         if (data != NULL)
  899.             data[*len] = '\0';          /* Null-terminate data to print it */
  900.         if (debug>1)                    /* Display incoming packet */
  901.         {
  902.             printmsg("  rpack type: %c\n",type);
  903.             printmsg("         num:  %d\n",*num);
  904.             printmsg("         len:  %d\n",*len);
  905.             if (data != NULL)
  906.                 printmsg("        data: \"%s\"\n",data);
  907.         }
  908.                                         /* Fold in bits 7,8 to compute */
  909.         cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
  910.  
  911.         if (cchksum != rchksum) return(FALSE);
  912.  
  913.         return(type);                       /* All OK, return packet type */
  914.     }
  915.     /* num == NULL so collect data for kermit */
  916.     dptr = data;
  917.     t = -1;
  918.     while (t)
  919.     {
  920.       switch(recstate)
  921.       {
  922.         case 'S':
  923.         while (1)            /* Wait for packet header */
  924.             getnext;
  925.         break;
  926.     case 'L':            /* get packet length */
  927.             getnext;            /* get next character */
  928.             cchksum = t;                    /* Start the checksum */
  929.             leng = unchar(t)-3;             /* Character count */
  930.         if (leng > MAXPACKSIZ)
  931.             leng = MAXPACKSIZ;
  932.         i = 0;
  933.         recstate = 'N';
  934.         /* Fall Through */
  935.  
  936.     case 'N':                /* get packet number */
  937.             getnext
  938.             cchksum = cchksum + t;          /* Update checksum */
  939.             numb = unchar(t);               /* Packet number */
  940.         recstate = 'T';
  941.         /* Fall Through */
  942.  
  943.     case 'T':                /* get packet type */
  944.             getnext;
  945.             cchksum = cchksum + t;          /* Update checksum */
  946.             type = t;                       /* Packet type */
  947.         recstate = 'D';
  948.         /* Fall Through */
  949.  
  950.     case 'D':                /* get packet data */
  951.             for (; i<leng; i++)             /* The data itself, if any */
  952.             {                               /* Loop for character count */
  953.                 getnext;
  954.                 cchksum = cchksum + t;      /* Update checksum */
  955.                 mybuf[i] = t;                /* Put it in the data buffer */
  956.             }
  957.         if (i == leng) 
  958.             recstate = 'C';
  959.         break;
  960.  
  961.     case 'C':
  962.             mybuf[leng] = 0;                 /* Mark the end of the data */
  963.             getnext;
  964.             rchksum = unchar(t);            /* Convert to numeric */
  965.         recstate = 'E';            /* Done with packet receipt */
  966.         t = 0;                /* Dispose of remaining data */
  967.       }
  968.     }
  969.     if (recstate == 'E') {
  970.         recstate = 'S';
  971.     if (sflg)
  972.     {
  973.         if (sendsw() != GETPACK)        /* Send the file(s) */
  974.                 return(kermterm());
  975.     }
  976.     else if (rflg)
  977.     {
  978.             if (recsw() != GETPACK)         /* Receive the file(s) */
  979.                 return(kermterm());
  980.     }
  981.     }
  982.     return(0);
  983. }
  984.  
  985.  
  986. /*
  987.  *  b u f i l l
  988.  *
  989.  *  Get a bufferful of data from the file that's being sent.
  990.  *  Only control-quoting is done; 8-bit & repeat count prefixes are
  991.  *  not handled.
  992.  */
  993.  
  994. bufill(buffer)
  995. char buffer[];                          /* Buffer */
  996. {
  997.     int i,                              /* Loop index */
  998.         t;                              /* Char read from file */
  999.     char t7;                            /* 7-bit version of above */
  1000.  
  1001.     i = 0;                              /* Init data buffer pointer */
  1002.     while((t = getc(fp)) != EOF)        /* Get the next character */
  1003.     {
  1004.         t7 = t & 0177;                  /* Get low order 7 bits */
  1005.  
  1006.         if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
  1007.         {                                   /* special handling? */
  1008.             if (t=='\n' && !image)
  1009.             {                           /* Do LF->CRLF mapping if !image */
  1010.                 buffer[i++] = quote;
  1011.                 buffer[i++] = ctl('\r');
  1012.             }
  1013.             buffer[i++] = quote;        /* Quote the character */
  1014.             if (t7 != quote)
  1015.             {
  1016.                 t = ctl(t);             /* and uncontrolify */
  1017.                 t7 = ctl(t7);
  1018.             }
  1019.         }
  1020.         if (image)
  1021.             buffer[i++] = t;            /* Deposit the character itself */
  1022.         else
  1023.             buffer[i++] = t7;
  1024.  
  1025.         if (i >= spsiz-8) return(i);    /* Check length */
  1026.     }
  1027.     if (i==0) return(EOF);              /* Wind up here only on EOF */
  1028.     return(i);                          /* Handle partial buffer */
  1029. }
  1030.  
  1031.  
  1032. /*
  1033.  *      b u f e m p
  1034.  *
  1035.  *  Put data from an incoming packet into a file.
  1036.  */
  1037.  
  1038. bufemp(buffer,len)
  1039. char  buffer[];                         /* Buffer */
  1040. int   len;                              /* Length */
  1041. {
  1042.     int i;                              /* Counter */
  1043.     char t;                             /* Character holder */
  1044.  
  1045. #ifdef EXTRADEBUG
  1046.         if (debug > 2) printmsg("Entered bufemp");
  1047. #endif
  1048.     for (i=0; i<len; i++)               /* Loop thru the data field */
  1049.     {
  1050.         t = buffer[i];                  /* Get character */
  1051.         if (t == MYQUOTE)               /* Control quote? */
  1052.         {                               /* Yes */
  1053.             t = buffer[++i];            /* Get the quoted character */
  1054.             if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
  1055.                 t = ctl(t);             /* No, uncontrollify it */
  1056.         }
  1057.         if (t==CR && !image)            /* Don't pass CR if not in image mode */
  1058.             continue;
  1059. #ifdef EXTRADEBUG
  1060.         if (debug > 2) printmsg("writing t=%c", t);
  1061. #endif
  1062.         putc(t,fp);
  1063.     }
  1064. }
  1065.  
  1066.  
  1067.  
  1068. /*
  1069.  *  g n x t f l
  1070.  *
  1071.  *  Get next file in a file group
  1072.  */
  1073.  
  1074. gnxtfl()
  1075. {
  1076.     if (filecount-- == 0) return FALSE; /* If no more, fail */
  1077.     if (debug) printmsg("   gnxtfl: filelist = \"%s\"\n",*filelist);
  1078.     filnam = *(filelist++);
  1079.     return TRUE;                   /* else succeed */
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  *  s p a r
  1085.  *
  1086.  *  Fill the data array with my send-init parameters
  1087.  *
  1088.  */
  1089.  
  1090. spar(data)
  1091. char data[];
  1092. {
  1093.     data[0] = tochar(MAXPACKSIZ);          /* Biggest packet I can receive */
  1094.     data[1] = tochar(reqtimint);           /* When I want to be timed out */
  1095.     data[2] = tochar(MYPAD);            /* How much padding I need */
  1096.     data[3] = ctl(MYPCHAR);             /* Padding character I want */
  1097.     data[4] = tochar(MYEOL);            /* End-Of-Line character I want */
  1098.     data[5] = MYQUOTE;                  /* Control-Quote character I send */
  1099. }
  1100.  
  1101.  
  1102. /*  r p a r
  1103.  *
  1104.  *  Get the other host's send-init parameters
  1105.  *
  1106.  */
  1107.  
  1108. rpar(data)
  1109. char data[];
  1110. {
  1111.     spsiz = unchar(data[0]);            /* Maximum send packet size */
  1112.     timint = unchar(data[1]);           /* When I should time out */
  1113.     if (timint > MAXTIM) timint = MAXTIM;
  1114.     if (timint < MINTIM) timint = MINTIM;
  1115.     pad = unchar(data[2]);              /* Number of pads to send */
  1116.     padchar = ctl(data[3]);             /* Padding character to send */
  1117.     eol = unchar(data[4]);              /* EOL character I must send */
  1118.     quote = data[5];                    /* Incoming data quote character */
  1119. }
  1120.  
  1121.  
  1122. /*
  1123.  *  Kermit printing routines:
  1124.  *
  1125.  *  printmsg -  like printf with "Kermit: " prepended
  1126.  *  prerrpkt - print contents of error packet received from remote host
  1127.  */
  1128.  
  1129.  
  1130. /*
  1131.  *  p r i n t m s g
  1132.  *
  1133.  *  Print message kermit window
  1134.  */
  1135.  
  1136. /*VARARGS1*/
  1137. printmsg(fmt, a1, a2, a3, a4, a5)
  1138. char *fmt;
  1139. {
  1140.     char *sbuf[100];
  1141.         w_output(kermwdes,"Kermit: ");
  1142.         sprintf(sbuf,fmt,a1,a2,a3,a4,a5);
  1143.         w_output(kermwdes,sbuf);
  1144.         w_output(kermwdes,"\n\r");
  1145. }
  1146.  
  1147.  
  1148. /*
  1149.  *  p r e r r p k t
  1150.  *
  1151.  *  Print contents of error packet received from remote host.
  1152.  */
  1153. prerrpkt(msg)
  1154. char *msg;
  1155. {
  1156.     printmsg("Kermit aborting with following error from remote host:\n%s",msg);
  1157.     return;
  1158. }
  1159.